#!/usr/bin/env python3
# Copyright (c) 2025 pony working team
# SPDX-License-Identifier: MulanPSL-2.0

import os
import re
import pickle
import shutil
import argparse
from menuconfig import menuconfig

if __name__ == "__main__":
    import libconf
else:
    from . import libconf


root_dir = os.path.abspath(os.path.dirname(__file__) + "/../..")

prjname = os.path.basename(os.getcwd())

usage_str = '''
    prj [-h] [-l] [-w <proj_dir> <board_name> [-f] [-u]] [-m] [-s <CONFIG_AA=x> [<CONFIG_BB=x> ...]]
        [-v <CONFIG_CC> [<CONFIG_DD> ...]] [-u]
'''

help_str = '''
optional arguments:
    -h                                          show this help message and exit
    -l                                          show all supported boards
    -w <proj_dir> <board_name>                  create a project for a board
    -f                                          force, if directory exist, delete it first
    -s <CONFIG_AA=x> [<CONFIG_BB=x> ...]        set kconfig components and variables
    -v <CONFIG_CC> [<CONFIG_DD> ...]            get kconfig components and variable values
    -m                                          open menuconfig cui
    -u                                          update config and project
'''

user_main = '''\
#include <kprintf.h>

int main (void)
{
    kprintf("hello world\\n");
    return 0;
}
'''


def main():
    global prjname

    parser = argparse.ArgumentParser(usage=usage_str, add_help=False)
    parser.add_argument("-w", "--workspace",  nargs=2)
    parser.add_argument("-f", "--force",      action='store_true')
    parser.add_argument("-s", "--set",        nargs="+")
    parser.add_argument("-v", "--value",      nargs="+")
    parser.add_argument('-m', '--menuconfig', action='store_true')
    parser.add_argument('-u', '--update',     action='store_true')
    parser.add_argument('-l', '--boards',   action='store_true')
    parser.add_argument('-h', '--help',       action='store_true')
    args = parser.parse_args()

    if args.help:
        parser.print_usage()
        print(help_str)
        quit()

    if args.boards:
        print("\n".join(libconf.get_boards().keys()))
        quit()

    if args.workspace:
        prjname = args.workspace[0]

    # create project or get project form current dir
    project = libconf.parse_workspace(args.workspace, args.force, args.update)

    # set the kconfig configuration file name in system env
    kconf = libconf.get_kconfig()

    # handle "-s CONFIG_XX=x" or "--set CONFIG_XX=x", component set command
    libconf.set_config(args.set)

    if not os.path.isfile("config/kconfig.mk"):
        kconf.write_config("config/kconfig.mk")

    # menu config
    if args.menuconfig:
        menuconfig(kconf)
        # sync settings incase user quited menuconfig without saving, if we do
        # not do this, the  kconfig.mk will be not aligned with kconf which is
        # updated by menuconfig but not saved!
        kconf.load_config("config/kconfig.mk", False)

    # update/create kconfig.h
    if not os.path.isfile("config/kconfig.h"):
        kconf.write_autoconf("config/kconfig.h")
    elif os.path.getmtime("config/kconfig.mk") > os.path.getmtime("config/kconfig.h"):
        kconf.write_autoconf("config/kconfig.h")

    # hande "-v" or "--value", get value
    if args.value:
        for v in args.value:
            match = re.match("CONFIG_([^=]+)", v)
            if not match:
                print(v + " not match the 'CONFIG_XX' format, value read ignored.")
                continue
            name = match.groups()[0]
            if name not in kconf.syms:
                print("kconfig symbol CONFIG_" + name +
                      " not exist, value read ignored.")
            else:
                print(v + "=" + kconf.syms[name].str_value)

    if not os.path.isfile("build.mk"):
        # copy default main.c
        shutil.copyfile(os.path.join(root_dir, "target/main.c"), "main.c")
        # create build.mk
        with open("build.mk", "w", encoding="utf-8") as f:
            f.write("src-y += *.c\n")

    if kconf.syms["USER_APP"].str_value == "y":
        if not os.path.isfile("syscall_stub.c"):
            with open("main.c", "w", encoding="utf-8") as f:
                f.write(user_main)
            os.system("make syscall_stub.c")
            with open("build.mk", "w", encoding="utf-8") as f:
                f.write("usr-y += *.c\n")

    # save prj
    if not os.path.isfile(prjname + ".prj"):
        with open(prjname + ".prj", "wb") as f:
            pickle.dump(project, f)

    # quit if NOIDE selected
    if kconf.syms["NOIDE"].str_value == "y":
        return

    # generate/update IDE project if any IDE support is enabled
    ide_project = prjname + "." + kconf.syms["IDE_EXT"].str_value
    if not os.path.isfile(ide_project):
        os.system("make gen-ide GENIDE=1")
    elif os.path.getmtime("config/kconfig.mk") > os.path.getmtime(ide_project) or args.update:
        if os.path.isfile("flags.ini"):
            os.remove("flags.ini")
        os.system("make gen-ide GENIDE=1")


if __name__ == "__main__":
    main()
